Interactive Element Macros
**Referenced Files in This Document** - [client-marquee.njk](file://src/_includes/macros/client-marquee.njk) - [cta-section.njk](file://src/_includes/macros/cta-section.njk) - [newsletter-signup.njk](file://src/_includes/macros/newsletter-signup.njk) - [polling-bar.njk](file://src/_includes/macros/polling-bar.njk) - [10-logo-marquee.css](file://src/assets/css/modules/10-logo-marquee.css) - [15-cta-section.css](file://src/assets/css/modules/15-cta-section.css) - [42-newsletter-signup-component.css](file://src/assets/css/modules/42-newsletter-signup-component.css) - [poll-bar-animation.js](file://src/assets/js/modules/poll-bar-animation.js) - [newsletter-spam-protection.js](file://src/assets/js/modules/newsletter-spam-protection.js) - [clients.json](file://src/_data/clients.json) - [polling.js](file://src/_data/polling.js)Table of Contents
- Introduction
- Project Structure
- Core Components
- Architecture Overview
- Detailed Component Analysis
- Dependency Analysis
- Performance Considerations
- Troubleshooting Guide
- Conclusion
Introduction
This document provides comprehensive documentation for interactive element macros designed to enhance user engagement across the site. It covers:
- Animated client showcase via a horizontally scrolling marquee with hover pause and optional grayscale effects
- Call-to-action sections with themed layouts and highlighted text support
- Newsletter subscription forms with ConvertKit integration, spam protection, and responsive designs
- Live polling displays with animated progress bars and real-time-like updates
Each macro’s parameters, CSS class mappings, JavaScript integration points, responsive behavior, accessibility considerations, and performance optimization strategies are explained with practical implementation guidance.
Project Structure
The interactive macros reside under the Eleventy includes/macros directory and are supported by dedicated CSS modules and lightweight JavaScript modules. Data sources provide dynamic content for marquee and polling visuals.
graph TB
subgraph "Macros"
CM["client-marquee.njk"]
CTASEC["cta-section.njk"]
NS["newsletter-signup.njk"]
PB["polling-bar.njk"]
end
subgraph "CSS Modules"
CMCSS["10-logo-marquee.css"]
CTACSS["15-cta-section.css"]
NSCSS["42-newsletter-signup-component.css"]
end
subgraph "JS Modules"
PBA["poll-bar-animation.js"]
NSP["newsletter-spam-protection.js"]
end
subgraph "Data"
CL["clients.json"]
PL["polling.js"]
end
CM --> CMCSS
CTASEC --> CTACSS
NS --> NSCSS
PB --> PBA
CM --- CL
PB --- PL
NS --> NSP
Diagram sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [10-logo-marquee.css:1-79](file://src/assets/css/modules/10-logo-marquee.css#L1-L79)
- [15-cta-section.css:1-101](file://src/assets/css/modules/15-cta-section.css#L1-L101)
- [42-newsletter-signup-component.css:1-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L1-L235)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
- [clients.json:1-104](file://src/_data/clients.json#L1-L104)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Section sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [10-logo-marquee.css:1-79](file://src/assets/css/modules/10-logo-marquee.css#L1-L79)
- [15-cta-section.css:1-101](file://src/assets/css/modules/15-cta-section.css#L1-L101)
- [42-newsletter-signup-component.css:1-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L1-L235)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
- [clients.json:1-104](file://src/_data/clients.json#L1-L104)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Core Components
This section outlines each macro’s purpose, parameters, and integration points.
-
Client Logo Marquee
- Purpose: Horizontal scrolling showcase of client logos with auto-play and hover pause
- Parameters:
- items: Array of logo objects with file and alt
- basePath: Base path for logo images (default: "/assets/repository/images/clients/")
- speed: Animation duration (default: "90s")
- grayscale: Toggle grayscale effect (default: true)
- CSS classes: logo-track-wrapper, logo-track, logo-item, no-grayscale
- Accessibility: Lazy loading on images; hover pause improves readability
- Performance: Double-length DOM to prevent jump; CSS transforms for smoothness
-
Call-to-Action Section
- Purpose: Prominent section with title, optional subtitle, and themed button
- Parameters:
- title: Section title
- buttonText: Button label (default: "Contact us today")
- buttonUrl: Button link (default: "/contact/")
- subtitle: Optional subtitle
- theme: Theme variant (default: "dark")
- highlightText: Text to highlight within title
- CSS classes: cta-section, cta-content, cta-title, cta-sub, cta-button, highlight
- Accessibility: Semantic heading hierarchy; focus-friendly button styles
-
Newsletter Subscription
- Purpose: Dual variants (full and compact) with ConvertKit integration and spam protection
- Parameters:
- title: Form title
- description: Description text
- buttonText: Submit button label
- variant: Layout mode ("full" or "compact")
- formId: ConvertKit form identifier
- CSS classes: newsletter-signup, newsletter-signup__content, newsletter-signup__form, footer-newsletter, footer-newsletter-form
- Spam protection: Honeypot field and submission timing check
- Accessibility: Proper labels and placeholders; required attributes for email
-
Polling Bar
- Purpose: Two-party preferred visualization with animated progress bars and contextual story
- Parameters:
- data: Object containing poll metrics (e.g., labor_tpp, liberal_tpp, primary vote breakdown)
- sourceText: Source attribution text
- isFallback: Flag indicating static/fallback data
- pages: Page-level content overrides for story and links
- CSS classes: poll-vis-container, poll-header-row, poll-bar-track, poll-bar-segment, poll-meta, poll-context, stat-box
- JS integration: IntersectionObserver triggers width animations on visibility
- Accessibility: Semantic headings and contrast-compliant colors
Section sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
Architecture Overview
The macros render HTML with specific class names. Styles are applied via dedicated CSS modules. JavaScript modules attach interactivity:
- Polling bars animate widths when they enter the viewport
- Newsletter forms gain anti-bot protections
- Marquee relies on CSS animations with hover pause
sequenceDiagram
participant TPL as "Template"
participant MAC as "Macro Renderer"
participant CSS as "CSS Module"
participant JS as "JS Module"
TPL->>MAC : Render macro with parameters
MAC-->>TPL : HTML with class names
TPL->>CSS : Apply styles matching class names
TPL->>JS : Initialize module on page load
JS->>JS : Observe elements and apply behavior
CSS-->>JS : Visual feedback (hover, transitions)
Diagram sources
- [client-marquee.njk:12-25](file://src/_includes/macros/client-marquee.njk#L12-L25)
- [cta-section.njk:2-16](file://src/_includes/macros/cta-section.njk#L2-L16)
- [newsletter-signup.njk:6-26](file://src/_includes/macros/newsletter-signup.njk#L6-L26)
- [polling-bar.njk:2-37](file://src/_includes/macros/polling-bar.njk#L2-L37)
- [10-logo-marquee.css:12-26](file://src/assets/css/modules/10-logo-marquee.css#L12-L26)
- [15-cta-section.css:5-101](file://src/assets/css/modules/15-cta-section.css#L5-L101)
- [42-newsletter-signup-component.css:6-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L235)
- [poll-bar-animation.js:3-17](file://src/assets/js/modules/poll-bar-animation.js#L3-L17)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
Detailed Component Analysis
Client Logo Marquee
- Rendering logic
- Accepts items array and optional basePath, speed, grayscale
- Ensures trailing slash on basePath
- Renders two identical sequences to enable seamless looping
- Applies grayscale class conditionally
- Styling and behavior
- Wrapper clips horizontally; track animates with CSS keyframes
- Hover pauses animation for readability
- Items scale and desaturate on hover; optional override class restores color
- Implementation example
- Use the macro with a data source providing logo file and alt text
- Adjust speed for performance or emphasis
- Accessibility and performance
- Images use lazy loading
- Hover pause reduces motion for sensitive users
- Double-length DOM prevents visible loop jumps
flowchart TD
Start(["Render Marquee"]) --> Validate["Validate items array"]
Validate --> |Invalid| End(["Exit"])
Validate --> BuildPath["Ensure basePath ends with '/'"]
BuildPath --> RenderTrack["Render logo-track with items x2"]
RenderTrack --> ApplyGrayscale["Apply grayscale class if enabled"]
ApplyGrayscale --> Animate["CSS animation runs at configured speed"]
Animate --> HoverPause["Hover pauses animation"]
HoverPause --> End
Diagram sources
- [client-marquee.njk:8-25](file://src/_includes/macros/client-marquee.njk#L8-L25)
- [10-logo-marquee.css:12-26](file://src/assets/css/modules/10-logo-marquee.css#L12-L26)
Section sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [10-logo-marquee.css:1-79](file://src/assets/css/modules/10-logo-marquee.css#L1-L79)
- [clients.json:1-104](file://src/_data/clients.json#L1-L104)
Call-to-Action Section
- Rendering logic
- Supports theme selection and optional highlightText replacement
- Conditionally renders subtitle
- Outputs a styled anchor as the primary action
- Styling and behavior
- Dark theme gradient background; light theme variants handled via body classes
- Animated button with pseudo-element fill and hover elevation
- Responsive typography using clamp for fluid headings
- Implementation example
- Provide title, optional subtitle, and button text/url
- Highlight key words by passing matching text as highlightText
- Accessibility and performance
- Semantic heading and paragraph structure
- Smooth transitions avoid jank on hover
flowchart TD
Start(["Render CTA"]) --> Theme["Apply theme attribute"]
Theme --> Title["Render title with optional highlight span"]
Title --> Subtitle{"Has subtitle?"}
Subtitle --> |Yes| RenderSub["Render subtitle paragraph"]
Subtitle --> |No| SkipSub["Skip subtitle"]
RenderSub --> Button["Render anchor button"]
SkipSub --> Button
Button --> End(["Complete"])
Diagram sources
- [cta-section.njk:1-17](file://src/_includes/macros/cta-section.njk#L1-L17)
- [15-cta-section.css:5-101](file://src/assets/css/modules/15-cta-section.css#L5-L101)
Section sources
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [15-cta-section.css:1-101](file://src/assets/css/modules/15-cta-section.css#L1-L101)
Newsletter Subscription
- Rendering logic
- Two variants: full (with name/email) and compact (email only)
- Integrates with ConvertKit via form action and formId
- Includes privacy notice and responsive layout
- Anti-spam protection
- Adds a hidden honeypot field
- Prevents submission if the field is filled or if submitted too quickly after page load
- Styling and responsiveness
- Full variant: centered columns with rounded inputs and gold-accented button
- Compact variant: footer-focused with minimal spacing
- Mobile-first layout stacks inputs on small screens
- Implementation example
- Set variant and formId from site data
- Provide optional title and description
- Accessibility and performance
- Required email field ensures valid input
- Focus states and transitions improve UX
sequenceDiagram
participant User as "User"
participant Form as "Newsletter Form"
participant Bot as "Spam Protection"
participant Service as "ConvertKit"
User->>Form : Fill inputs
Form->>Bot : Attach hidden honeypot field
User->>Form : Submit
Form->>Bot : Validate honeypot and timing
Bot-->>Form : Allow or block submission
Form->>Service : POST to ConvertKit endpoint
Service-->>User : Confirmation
Diagram sources
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [42-newsletter-signup-component.css:6-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L6-L235)
Section sources
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
- [42-newsletter-signup-component.css:1-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L1-L235)
Polling Bar
- Rendering logic
- Displays two-party preferred segments with animated widths
- Provides contextual story content and statistics grid
- Supports fallback mode and page-level content overrides
- JavaScript animation
- Uses IntersectionObserver to animate widths when segments become visible
- Threshold set to trigger animation upon partial visibility
- Styling and responsiveness
- Clear color coding for parties; serif-based typography for story headings
- Stat boxes with color-coded values; small print for margins and sample sizes
- Implementation example
- Pass data from a data source (e.g., polling.js) to macro
- Optionally override story and links via pages parameter
- Accessibility and performance
- Contrast-compliant colors aid readability
- Animations trigger only on visibility to reduce unnecessary work
sequenceDiagram
participant DOM as "Polling Bar DOM"
participant IO as "IntersectionObserver"
participant JS as "initPollAnimation"
participant Style as "CSS Width"
DOM->>JS : Elements with data-value present
JS->>IO : Observe elements with threshold
IO-->>JS : Element enters viewport
JS->>DOM : Set inline width to dataset value
IO-->>JS : Stop observing element
DOM->>Style : CSS transitions animate width
Diagram sources
- [polling-bar.njk:2-37](file://src/_includes/macros/polling-bar.njk#L2-L37)
- [poll-bar-animation.js:3-17](file://src/assets/js/modules/poll-bar-animation.js#L3-L17)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Section sources
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Dependency Analysis
- Macro-to-CSS mapping
- client-marquee.njk -> 10-logo-marquee.css
- cta-section.njk -> 15-cta-section.css
- newsletter-signup.njk -> 42-newsletter-signup-component.css
- Macro-to-JavaScript mapping
- polling-bar.njk -> poll-bar-animation.js
- newsletter-signup.njk -> newsletter-spam-protection.js
- Data dependencies
- client-marquee.njk -> clients.json
- polling-bar.njk -> polling.js
graph LR
CM["client-marquee.njk"] --> CMCSS["10-logo-marquee.css"]
CTASEC["cta-section.njk"] --> CTACSS["15-cta-section.css"]
NS["newsletter-signup.njk"] --> NSCSS["42-newsletter-signup-component.css"]
PB["polling-bar.njk"] --> PBA["poll-bar-animation.js"]
NS --> NSP["newsletter-spam-protection.js"]
CM --- CL["clients.json"]
PB --- PL["polling.js"]
Diagram sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [10-logo-marquee.css:1-79](file://src/assets/css/modules/10-logo-marquee.css#L1-L79)
- [15-cta-section.css:1-101](file://src/assets/css/modules/15-cta-section.css#L1-L101)
- [42-newsletter-signup-component.css:1-235](file://src/assets/css/modules/42-newsletter-signup-component.css#L1-L235)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
- [clients.json:1-104](file://src/_data/clients.json#L1-L104)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Section sources
- [client-marquee.njk:1-27](file://src/_includes/macros/client-marquee.njk#L1-L27)
- [cta-section.njk:1-18](file://src/_includes/macros/cta-section.njk#L1-L18)
- [newsletter-signup.njk:1-28](file://src/_includes/macros/newsletter-signup.njk#L1-L28)
- [polling-bar.njk:1-39](file://src/_includes/macros/polling-bar.njk#L1-L39)
- [poll-bar-animation.js:1-20](file://src/assets/js/modules/poll-bar-animation.js#L1-L20)
- [newsletter-spam-protection.js:1-24](file://src/assets/js/modules/newsletter-spam-protection.js#L1-L24)
- [clients.json:1-104](file://src/_data/clients.json#L1-L104)
- [polling.js:1-17](file://src/_data/polling.js#L1-L17)
Performance Considerations
- CSS animations
- Prefer transform and opacity for GPU acceleration
- Use hover to pause long-running animations for readability
- JavaScript observers
- Trigger animations only on visibility to minimize layout work
- Unobserve elements after initial animation to reduce overhead
- Forms
- Lazy-load images in marquees
- Keep form layouts responsive to reduce reflows on small screens
- Data-driven rendering
- Use concise data structures for marquee and polling to avoid heavy computations
[No sources needed since this section provides general guidance]
Troubleshooting Guide
- Marquee not animating
- Verify animation-duration is set and CSS keyframes are present
- Ensure items array is populated and basePath ends with "/"
- Polling bars not animating
- Confirm elements have data-value attributes and are observed by IntersectionObserver
- Check that the script is initialized on page load
- Newsletter form submits immediately
- Ensure the honeypot field is appended and submission timing is validated
- Confirm the form action points to the correct ConvertKit endpoint
- Accessibility issues
- Provide alt text for marquee images
- Use proper labels and placeholders for form inputs
- Ensure sufficient color contrast in themed sections
Section sources
- [client-marquee.njk:12-25](file://src/_includes/macros/client-marquee.njk#L12-L25)
- [poll-bar-animation.js:3-17](file://src/assets/js/modules/poll-bar-animation.js#L3-L17)
- [newsletter-spam-protection.js:3-23](file://src/assets/js/modules/newsletter-spam-protection.js#L3-L23)
- [10-logo-marquee.css:12-26](file://src/assets/css/modules/10-logo-marquee.css#L12-L26)
- [42-newsletter-signup-component.css:125-137](file://src/assets/css/modules/42-newsletter-signup-component.css#L125-L137)
Conclusion
These interactive element macros deliver engaging, accessible, and performant UI components:
- The client marquee provides a polished brand showcase with smooth animations
- The CTA section offers flexible theming and prominent call-to-action presentation
- The newsletter signup integrates seamlessly with ConvertKit while protecting against spam
- The polling bar delivers compelling data visualization with efficient, on-demand animations
By following the parameter configurations, CSS class mappings, and JavaScript integration points outlined here, teams can confidently implement and maintain these components across the site.